{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# 作业四：撰写项目README并完成开源\n",
    "\n",
    "## 评分标准\n",
    "1.格式规范（有至少3个小标题，内容完整），一个小标题5分，最高20分\n",
    "\n",
    "2.图文并茂，一张图5分，最高20分\n",
    "\n",
    "3.有可运行的代码，且代码内有详细注释，20分\n",
    "\n",
    "4.代码开源到github，15分\n",
    "\n",
    "5.代码同步到gitee，5分\n",
    "\n",
    "## 作业目的\n",
    "使用MarkDown撰写项目并且学会使用开源工具。\n",
    "\n",
    "\n",
    "\n",
    "## 参考资料：\n",
    "- [如何写好一篇高质量的精选项目？](https://aistudio.baidu.com/aistudio/projectdetail/2175889)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 作业内容\n",
    "把自己的项目描述放在对应区域中，形成一个完整流程项目，并且在最后声明自己项目的github和gitee链接\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **********除了下面这个，群里发的我也参与了，希望老师可以根据这两个高的给我个分，谢谢**********\n",
    "![](https://ai-studio-static-online.cdn.bcebos.com/25aff9c8e5124cff9acedeeec90804b9afde213964624bea885090e4588275f3)\n",
    "\n",
    "![](https://ai-studio-static-online.cdn.bcebos.com/c5a93955c1d44f5ebb44add4b353bdf27e2d69e3182944ec924caf8bf5e24ef1)\n",
    "\n",
    "# 我更新的项目原链接：[在这里](https://aistudio.baidu.com/aistudio/projectdetail/505168)\n",
    "# 更新为飞桨2.2后的链接[在这里](https://aistudio.baidu.com/aistudio/projectdetail/3531697?forkThirdPart=1)"
   ]
  },
  {
   "attachments": {
    "28ba2597-5031-4e7e-a70c-19d8a096da9b.jpg": {
     "image/jpeg": "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"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一、项目背景介绍\n",
    "毛笔书法是中国特有的一种传统艺术。古往今来，中国汉字是劳动人民创造的，开始以图画形式表示文字，经过几千年的发展，演变成了当今的文字，古代长期用毛笔写字，便产生了书法。均以毛笔书写汉字为主。 判断书法作品的优劣主要通过字体的线条，流畅性，还有整体性。中国是书法艺术文化的发源地，也是最早使用毛笔的国家。我国毛笔书法家层出不穷，像王羲之，颜真卿，怀素，苏东坡，黄庭坚，米芾，王铎，柳公权，以及近代的沙孟海，启功，刘惠浦（在世）等，这些文学雅士都是功力高深的书法大家。毛笔书法字体识别，能够为毛笔书法艺术做出贡献。\n",
    "\n",
    "康有为在《广艺双楫•十六宗》中，提出了自己对书法鉴赏的十条评论标准，谓之“十美”：“一曰魄力雄强，二曰气象辉穆，三曰笔法跳越，四曰点画峻厚，五曰意态奇逸，六曰精神飞动，七曰兴趣酣足，八曰骨发洞达，九曰结构天成，十曰血肉丰美。”评鉴、赏读书法作品，大可从这么几个方面着眼：\n",
    "\n",
    "一、字之笔画变化调和，概论其长短相辅、粗细相照、浓淡相应在结字空间和通篇作品空间的相互调和。\n",
    "\n",
    "![](https://ai-studio-static-online.cdn.bcebos.com/f8ab872963604d97a6f420ca1b21c2b173973f777c3348c5bad2e8c6519308e2)\n",
    "\n",
    "\n",
    "二、字之“重心”位置变化调和，概括字的最终形态形成，其重心位置不一，相互调和，独字予人稳健之感，斜而不倒；字字相互照应，相得益彰。\n",
    "\n",
    "![](https://ai-studio-static-online.cdn.bcebos.com/4210e442008e4eb2abc220e90b40457f167cf594231c44aaba7bd43ba44a9a4f)\n",
    "\n",
    "\n",
    "三、字之气势变化调和，概括字的起笔、收笔之势多样，前后呼应，字字相辅相成的调和。\n",
    "\n",
    "![672931322a58497dadae8d3ffc2fbb8d2c72fecb65444fc38a8f0f49163e7575.jpg](attachment:28ba2597-5031-4e7e-a70c-19d8a096da9b.jpg)\n",
    "\n",
    "\n",
    "由上面可见为了欣赏大师的作品，作为一个之前未了解过的萌新，很难抓住重点去观摩学习，面对不同的作品无法区分其是哪家之作，进而无法快速进行归纳总结。\n",
    "为解决因手写书法作品种类繁多而识别困难的问题, 降低人们观赏大师书法的门槛, 以20位中国著名书法家的风格编写的汉字作品为数据集，可以实现快速对书法作品进行分类，降低人工鉴别时间成本。计算能力的提高、书法作品的发展，使得传统人工分析中存在的问题通过人工智能将逐渐得到改善或解决。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 二、数据介绍\n",
    "\n",
    "书法风格数据集来源于AIstudio的书法风格公开数据集，是一个以20位中国著名书法家的风格编写的汉字作品的数据集。\n",
    "\n",
    "这是一个以20位中国著名书法家的风格编写的汉字作品的数据集。每个子集中有1000-7000张jpg图像（平均5251张图像）。每张图像的尺寸为64 * 64，代表一个汉字。数据集分为训练集（80％）和测试集（20％）。书法家的姓名缩写用作标签。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 三、模型介绍\n",
    "我们采用paddleDetection套件实现一个书法图像分类系统。检测模型采用PP-YOLOv3，骨干网络采用ResNet-50。 对于数据的标注，我们主要标注了大师的名字。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 四、模型训练\n",
    "该部分主要是实践部分，也是相对来说话费时间最长的一部分，该部分主要展示模型训练的内容，同时向大家讲解模型参数的设置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 解压你所挂载的数据集在同级目录下\n",
    "# !unzip -oq data/xxx/xxx.zip -d data/xxx\n",
    "!unzip -oq /home/aistudio/data/data86197/ChineseCalligraphyStyles.zip -d work\n",
    "\n",
    "\n",
    "# 查看数据集的目录结构\n",
    "# !tree data/xxx -d\n",
    "!tree work/ -d\n",
    "# ! tree samples -d\n",
    "\n",
    "# 样例：语义分割数据集抽样可视化\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "plt.imshow(cv2.imread(\"work/train/sgt/0019.jpg\"))\n",
    "\n",
    "image_path_list = ['work/test/bdsr/1634.jpg', 'work/test/bdsr/1656.jpg']\n",
    "\n",
    "plt.figure(figsize=(8, 8))\n",
    "for i in range(len(image_path_list)):\n",
    "    plt.subplot(len(image_path_list), 2, i*2+1)\n",
    "    plt.title(image_path_list[i])\n",
    "    plt.imshow(cv2.imread(image_path_list[i])[:, :, ::-1])\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 引入需要的模块\n",
    "import os\n",
    "import zipfile\n",
    "import random\n",
    "import json\n",
    "import paddle\n",
    "import sys\n",
    "import numpy as np\n",
    "from PIL import Image\n",
    "import matplotlib.pyplot as plt\n",
    "from paddle.io import Dataset\n",
    "random.seed(200)\n",
    "\n",
    "def get_data_list(target_path,train_list_path,eval_list_path):\n",
    "    '''\n",
    "    生成数据列表\n",
    "    '''\n",
    "    #存放所有类别的信息\n",
    "    class_detail = []\n",
    "    #获取所有类别保存的文件夹名称\n",
    "    data_list_path=target_path+\"shufa/\"\n",
    "    class_dirs = os.listdir(data_list_path)  \n",
    "    #总的图像数量\n",
    "    all_class_images = 0\n",
    "    #存放类别标签\n",
    "    class_label=0\n",
    "    #存放类别数目\n",
    "    class_dim = 0\n",
    "    #存储要写进eval.txt和train.txt中的内容\n",
    "    trainer_list=[]\n",
    "    eval_list=[]\n",
    "    class_flag=0\n",
    "    class_dim_count=0\n",
    "    #读取每个类别，['baihe', 'gouqi','jinyinhua','huaihua','dangshen']\n",
    "    for class_dir in class_dirs:\n",
    "        if class_dir != \".DS_Store\":\n",
    "            class_dim_count+=1\n",
    "            #每个类别的信息\n",
    "            \n",
    "            eval_sum = 0\n",
    "            trainer_sum = 0\n",
    "            #统计每个类别有多少张图片\n",
    "            class_sum = 0\n",
    "            #获取类别路径 \n",
    "            path = data_list_path  + class_dir\n",
    "            Tpath=os.listdir(path)\n",
    "            cls_name=''\n",
    "            for paths in Tpath:\n",
    "                \n",
    "                class_dim += 1\n",
    "                class_detail_list = {}\n",
    "                # 获取所有图片\n",
    "                paths=path+'/'+paths\n",
    "                cls_name=paths\n",
    "                img_paths = os.listdir(paths)\n",
    "                for img_path in img_paths:                                  # 遍历文件夹下的每个图片\n",
    "                    name_path = paths + '/' + img_path                       # 每张图片的路径\n",
    "                    if 'test' in paths :                                  \n",
    "                        eval_sum += 1                                       # test_sum为测试数据的数目\n",
    "                        eval_list.append(name_path + \"\\t%d\" % class_label + \"\\n\")\n",
    "                    elif 'train' in paths :\n",
    "                        trainer_sum += 1 \n",
    "                        trainer_list.append(name_path + \"\\t%d\" % class_label + \"\\n\")#trainer_sum测试数据的数目\n",
    "                    class_sum += 1                                          #每类图片的数目\n",
    "                    all_class_images += 1                                   #所有类图片的数目\n",
    "            \n",
    "                if class_label<=20 :\n",
    "                    if class_flag<1:\n",
    "                        # 说明的json文件的class_detail数据\n",
    "                        class_detail_list['class_name'] = cls_name             #类别名称\n",
    "                        class_detail_list['class_label'] = class_label          #类别标签\n",
    "                        class_detail_list['class_eval_images'] = eval_sum       #该类数据的测试集数目\n",
    "                        class_detail_list['class_trainer_images'] = trainer_sum #该类数据的训练集数目\n",
    "                        class_detail.append(class_detail_list)\n",
    "                        \n",
    "                        #初始化标签列表\n",
    "                        train_parameters['label_dict'][str(class_label)] = cls_name\n",
    "                    else:\n",
    "                        if eval_sum!=0 :\n",
    "                            class_detail[class_label]['class_eval_images']=eval_sum;\n",
    "                        if trainer_sum!=0:\n",
    "                            class_detail[class_label]['class_trainer_images']=trainer_sum;\n",
    "                    if class_label==19:\n",
    "                        class_flag=2\n",
    "            \n",
    "                class_label += 1 \n",
    "                if class_label==20:\n",
    "                    class_label=0\n",
    "    \n",
    "             \n",
    "                \n",
    "            \n",
    "\n",
    "            \n",
    "            \n",
    "    #初始化分类数\n",
    "    train_parameters['class_dim'] = int(class_dim/class_dim_count)\n",
    "  \n",
    "    # #乱序  \n",
    "    random.shuffle(eval_list)\n",
    "\n",
    "    if os.path.exists(eval_list_path): # 如果文件存在\n",
    "        os.remove(eval_list_path) # 则删除\n",
    "    if os.path.exists(train_list_path): # 如果文件存在\n",
    "        os.remove(train_list_path) # 则删除\n",
    "\n",
    "\n",
    "    with open(eval_list_path, 'a') as f:\n",
    "        for eval_image in eval_list:\n",
    "            f.write(eval_image) \n",
    "            \n",
    "    random.shuffle(trainer_list)\n",
    "    with open(train_list_path, 'a') as f2:\n",
    "        for train_image in trainer_list:\n",
    "            f2.write(train_image) \n",
    "\n",
    "    # 说明的json文件信息\n",
    "    readjson = {}\n",
    "    readjson['all_class_name'] = data_list_path                  #文件父目录\n",
    "    readjson['all_class_images'] = all_class_images\n",
    "    readjson['class_detail'] = class_detail\n",
    "    jsons = json.dumps(readjson, sort_keys=True, indent=4, separators=(',', ': '))\n",
    "\n",
    "\n",
    "    if os.path.exists(train_parameters['readme_path']): # 如果文件存在\n",
    "        os.remove(train_parameters['readme_path']) # 则删除\n",
    "    with open(train_parameters['readme_path'],'w') as f:\n",
    "        f.write(jsons)\n",
    "    print ('生成数据列表完成！')\n",
    "\n",
    "train_parameters = {\n",
    "    \"target_path\":\"/home/aistudio/data/\",                     #图像相关路径\n",
    "    \"train_list_path\": \"/home/aistudio/data/train.txt\",       #train.txt路径\n",
    "    \"test_list_path\": \"/home/aistudio/data/test.txt\",         #eval.txt路径\n",
    "    \"label_dict\":{},                                          #标签字典\n",
    "    \"readme_path\": \"/home/aistudio/data/readme.json\",         #readme.json路径\n",
    "    \"class_dim\": -1,                                          #分类数\n",
    "}\n",
    "\n",
    "target_path=train_parameters['target_path']\n",
    "train_list_path=train_parameters['train_list_path']\n",
    "test_list_path=train_parameters['test_list_path']\n",
    "get_data_list(target_path,train_list_path,test_list_path)\n",
    "print(train_parameters)\n",
    "\n",
    "# 定义数据读取器\n",
    "class dataset(Dataset):\n",
    "    def __init__(self, data_path, mode='train'):\n",
    "        \"\"\"\n",
    "        数据读取器\n",
    "        :param data_path: 数据集所在路径\n",
    "        :param mode: train or eval\n",
    "        \"\"\"\n",
    "        super().__init__()\n",
    "        self.data_path = data_path\n",
    "        self.img_paths = []\n",
    "        self.labels = []\n",
    "\n",
    "        if mode == 'train':\n",
    "            with open(os.path.join(self.data_path, \"train.txt\"), \"r\", encoding=\"utf-8\") as f:\n",
    "                self.info = f.readlines()\n",
    "            for img_info in self.info:\n",
    "                img_path, label = img_info.strip().split('\\t')\n",
    "                self.img_paths.append(img_path)\n",
    "                self.labels.append(int(label))\n",
    "\n",
    "        else:\n",
    "            with open(os.path.join(self.data_path, \"test.txt\"), \"r\", encoding=\"utf-8\") as f:\n",
    "                self.info = f.readlines()\n",
    "            for img_info in self.info:\n",
    "                img_path, label = img_info.strip().split('\\t')\n",
    "                self.img_paths.append(img_path)\n",
    "                self.labels.append(int(label))\n",
    "\n",
    "\n",
    "    def __getitem__(self, index):\n",
    "        \"\"\"\n",
    "        获取一组数据\n",
    "        :param index: 文件索引号\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        # 第一步打开图像文件并获取label值\n",
    "        img_path = self.img_paths[index]\n",
    "        img = Image.open(img_path)\n",
    "        if img.mode != 'RGB':\n",
    "            img = img.convert('RGB') \n",
    "        img = img.resize((224, 224), Image.BILINEAR)\n",
    "        #img = rand_flip_image(img)\n",
    "        img = np.array(img).astype('float32')\n",
    "        img = img.transpose((2, 0, 1)) / 255\n",
    "        label = self.labels[index]\n",
    "        label = np.array([label], dtype=\"int64\")\n",
    "        return img, label\n",
    "\n",
    "    def print_sample(self, index: int = 0):\n",
    "        print(\"文件名\", self.img_paths[index], \"\\t标签值\", self.labels[index])\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.img_paths)\n",
    "\n",
    "#训练数据加载\n",
    "train_dataset = dataset('data/',mode='train')\n",
    "train_loader = paddle.io.DataLoader(train_dataset, batch_size=32, shuffle=True)\n",
    "#评估数据加载\n",
    "eval_dataset = dataset('data/',mode='eval')\n",
    "eval_loader = paddle.io.DataLoader(eval_dataset, batch_size = 8, shuffle=False)\n",
    "\n",
    "\n",
    "print(train_dataset.data_path,len(train_dataset.img_paths),len(train_dataset.labels))\n",
    "img,label=train_dataset.__getitem__(0)\n",
    "print(img.shape,label)\n",
    "\n",
    "# 定义卷积池化网络\n",
    "class ConvPool(paddle.nn.Layer):\n",
    "    '''卷积+池化'''\n",
    "    def __init__(self,\n",
    "                 num_channels,\n",
    "                 num_filters, \n",
    "                 filter_size,\n",
    "                 pool_size,\n",
    "                 pool_stride,\n",
    "                 groups,\n",
    "                 conv_stride=1, \n",
    "                 conv_padding=1,\n",
    "                 ):\n",
    "        super(ConvPool, self).__init__()  \n",
    "\n",
    "        # groups代表卷积层的数量\n",
    "        for i in range(groups):\n",
    "            self.add_sublayer(   #添加子层实例\n",
    "                'bb_%d' % i,\n",
    "                paddle.nn.Conv2D(         # layer\n",
    "                in_channels=num_channels, #通道数\n",
    "                out_channels=num_filters,   #卷积核个数\n",
    "                kernel_size=filter_size,   #卷积核大小\n",
    "                stride=conv_stride,        #步长\n",
    "                padding = conv_padding,    #padding\n",
    "                )\n",
    "            )\n",
    "            self.add_sublayer(\n",
    "                'relu%d' % i,\n",
    "                paddle.nn.ReLU()\n",
    "            )\n",
    "            num_channels = num_filters\n",
    "            \n",
    "\n",
    "        self.add_sublayer(\n",
    "            'Maxpool',\n",
    "            paddle.nn.MaxPool2D(\n",
    "            kernel_size=pool_size,           #池化核大小\n",
    "            stride=pool_stride               #池化步长\n",
    "            )\n",
    "        )\n",
    "\n",
    "    def forward(self, inputs):\n",
    "        x = inputs\n",
    "        for prefix, sub_layer in self.named_children():\n",
    "            # print(prefix,sub_layer)\n",
    "            x = sub_layer(x)\n",
    "        return x\n",
    "\n",
    "# VGG网络\n",
    "class VGGNet(paddle.nn.Layer):\n",
    "    def __init__(self):\n",
    "        super(VGGNet, self).__init__()       \n",
    "        # 5个卷积池化操作\n",
    "        self.convpool01 = ConvPool(\n",
    "            3, 64, 3, 2, 2, 2)  #3:通道数，64：卷积核个数，3:卷积核大小，2:池化核大小，2:池化步长，2:连续卷积个数\n",
    "        self.convpool02 = ConvPool(\n",
    "            64, 128, 3, 2, 2, 2)\n",
    "        self.convpool03 = ConvPool(\n",
    "            128, 256, 3, 2, 2, 3) \n",
    "        self.convpool04 = ConvPool(\n",
    "            256, 512, 3, 2, 2, 3)\n",
    "        self.convpool05 = ConvPool(\n",
    "            512, 512, 3, 2, 2, 3)       \n",
    "        self.pool_5_shape = 512 * 7* 7\n",
    "        # 三个全连接层\n",
    "        self.fc01 = paddle.nn.Linear(self.pool_5_shape, 4096)\n",
    "        self.drop1 = paddle.nn.Dropout(p=0.5)\n",
    "        self.fc02 = paddle.nn.Linear(4096, 4096)\n",
    "        self.drop2 = paddle.nn.Dropout(p=0.5)\n",
    "        self.fc03 = paddle.nn.Linear(4096, train_parameters['class_dim'])\n",
    "\n",
    "    def forward(self, inputs, label=None):\n",
    "        # print('input_shape:', inputs.shape) #[8, 3, 224, 224]\n",
    "        \"\"\"前向计算\"\"\"\n",
    "        out = self.convpool01(inputs)\n",
    "        # print('convpool01_shape:', out.shape)           #[8, 64, 112, 112]\n",
    "        out = self.convpool02(out)\n",
    "        # print('convpool02_shape:', out.shape)           #[8, 128, 56, 56]\n",
    "        out = self.convpool03(out)\n",
    "        # print('convpool03_shape:', out.shape)           #[32, 256, 28, 28]\n",
    "        out = self.convpool04(out)\n",
    "        # print('convpool04_shape:', out.shape)           #[32, 512, 14, 14]\n",
    "        out = self.convpool05(out)\n",
    "        # print('convpool05_shape:', out.shape)           #[32, 512, 7, 7]         \n",
    "\n",
    "        out = paddle.reshape(out, shape=[-1, 512*7*7])\n",
    "        out = self.fc01(out)\n",
    "        out = self.drop1(out)\n",
    "        out = self.fc02(out)\n",
    "        out = self.drop2(out)\n",
    "        out = self.fc03(out)\n",
    "        \n",
    "\n",
    "        if label is not None:\n",
    "            acc = paddle.metric.accuracy(input=out, label=label)\n",
    "            return out, acc\n",
    "        else:\n",
    "            return out\n",
    "            \n",
    "# 折线图，用于观察训练过程中loss和acc的走势\n",
    "def draw_process(title,color,iters,data,label):\n",
    "    plt.title(title, fontsize=24)\n",
    "    plt.xlabel(\"iter\", fontsize=20)\n",
    "    plt.ylabel(label, fontsize=20)\n",
    "    plt.plot(iters, data,color=color,label=label) \n",
    "    plt.legend()\n",
    "    plt.grid()\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "print(train_parameters['class_dim'])\n",
    "\n",
    "model = VGGNet()\n",
    "model.train()\n",
    "# 配置loss函数\n",
    "cross_entropy = paddle.nn.CrossEntropyLoss()\n",
    "# 配置参数优化器\n",
    "optimizer = paddle.optimizer.Adam(learning_rate=train_parameters['learning_strategy']['lr'],\n",
    "                                  parameters=model.parameters()) \n",
    "\n",
    "steps = 0\n",
    "Iters, total_loss, total_acc = [], [], []\n",
    "\n",
    "for epo in range(train_parameters['num_epochs']):\n",
    "    for _, data in enumerate(train_loader()):\n",
    "        steps += 1\n",
    "        x_data = data[0]\n",
    "        y_data = data[1]\n",
    "        predicts, acc = model(x_data, y_data)\n",
    "        loss = cross_entropy(predicts, y_data)\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        optimizer.clear_grad()\n",
    "        if steps % train_parameters[\"skip_steps\"] == 0:\n",
    "            Iters.append(steps)\n",
    "            total_loss.append(loss.numpy()[0])\n",
    "            total_acc.append(acc.numpy()[0])\n",
    "            #打印中间过程\n",
    "            print('epo: {}, step: {}, loss is: {}, acc is: {}'\\\n",
    "                  .format(epo, steps, loss.numpy(), acc.numpy()))\n",
    "        #保存模型参数\n",
    "        if steps % train_parameters[\"save_steps\"] == 0:\n",
    "            save_path = train_parameters[\"checkpoints\"]+\"/\"+\"save_dir_\" + str(steps) + '.pdparams'\n",
    "            print('save model to: ' + save_path)\n",
    "            paddle.save(model.state_dict(),save_path)\n",
    "paddle.save(model.state_dict(),train_parameters[\"checkpoints\"]+\"/\"+\"save_dir_final.pdparams\")\n",
    "draw_process(\"trainning loss\",\"red\",Iters,total_loss,\"trainning loss\")\n",
    "draw_process(\"trainning acc\",\"green\",Iters,total_acc,\"trainning acc\")\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 五、模型评估\n",
    "该部分主要是对训练好的模型进行评估，可以是用验证集进行评估，或者是直接预测结果。评估结果和预测结果尽量展示出来，增加吸引力。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# 模型评估\n",
    "# 加载训练过程保存的最后一个模型\n",
    "model__state_dict = paddle.load('work/checkpoints/save_dir_final.pdparams')\n",
    "model_eval = VGGNet()\n",
    "model_eval.set_state_dict(model__state_dict) \n",
    "model_eval.eval()\n",
    "accs = []\n",
    "# 开始评估\n",
    "for _, data in enumerate(eval_loader()):\n",
    "    x_data = data[0]\n",
    "    y_data = data[1]\n",
    "    predicts = model_eval(x_data)\n",
    "    acc = paddle.metric.accuracy(predicts, y_data)\n",
    "    accs.append(acc.numpy()[0])\n",
    "print('模型在验证集上的准确率为：',np.mean(accs))\n",
    "\n",
    "def load_image(img_path):\n",
    "    '''\n",
    "    预测图片预处理\n",
    "    '''\n",
    "    img = Image.open(img_path) \n",
    "    if img.mode != 'RGB': \n",
    "        img = img.convert('RGB') \n",
    "    img = img.resize((224, 224), Image.BILINEAR)\n",
    "    img = np.array(img).astype('float32') \n",
    "    img = img.transpose((2, 0, 1)) / 255 # HWC to CHW 及归一化\n",
    "    return img\n",
    "\n",
    "\n",
    "label_dic = train_parameters['label_dict']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 六、总结与升华\n",
    "不足之处，可以调调参，现在参数不是最优"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 七、个人总结\n",
    "个人学生小白，正在学cv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 提交链接\n",
    "aistudio链接： https://aistudio.baidu.com/aistudio/projectdetail/3483040\n",
    "\n",
    "github链接：\n",
    "\n",
    "gitee链接："
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "py35-paddle1.2.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
